package com.bigzero.workflow.modules.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bigzero.workflow.common.model.*;
import com.bigzero.workflow.common.utils.JwtUtil;
import com.bigzero.workflow.modules.system.constants.UserPermCacheConstant;
import com.bigzero.workflow.modules.system.dao.MenuDao;
import com.bigzero.workflow.modules.system.dao.RoleDao;
import com.bigzero.workflow.modules.system.dao.UserRoleDao;
import com.bigzero.workflow.modules.system.entity.MenuEntity;
import com.bigzero.workflow.modules.system.entity.RoleEntity;
import com.bigzero.workflow.modules.system.query.MenuQuery;
import com.bigzero.workflow.modules.system.service.MenuService;
import com.bigzero.workflow.modules.system.service.UserCacheService;
import com.bigzero.workflow.modules.system.service.UserRoleService;
import com.bigzero.workflow.modules.system.vo.MenuVo;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 用户缓存service实现
 *
 * @author fanxinxiong
 * @since 2023-06-11
 */
@Slf4j
@Component
public class UserCacheServiceImpl implements UserCacheService {

    /**
     * 是否拦截header
     */
    @Value("${workflow.header.intercept}")
    private boolean intercept;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private RoleDao roleDao;
    @Resource
    private MenuDao menuDao;
    @Resource
    private UserRoleDao userRoleDao;
    @Resource
    private MenuService menuService;
    @Resource
    private UserRoleService userRoleService;
    @Resource
    RedisTemplate<String, Object> redisTemplate;


    /**
     * 根据用户编码获取用户权限信息
     * @param tokenInfo 用户token信息
     * @return UserPermInfo
     */
    @Cacheable(value = UserPermCacheConstant.SYS_USER_PERM_INFO_CACHE_EXPIRE, key = "#tokenInfo.username", unless = "#result == null ")
    public UserPermInfo getUserPermInfoByTokenInfo(TokenInfo tokenInfo){
        //获取设置用户权限缓存
        return getSetUserPermInfoCache(tokenInfo);
    }

    /**
     * 解析token
     * @param token token信息
     * @return TokenInfo
     */
    @Cacheable(value = UserPermCacheConstant.TOKEN_INFO_CACHE_EXPIRE, key = "#token", unless = "#result == null ")
    public TokenInfo getTokenInfo(String token){
        TokenInfo tokenInfo = null;
        try{
            tokenInfo = jwtUtil.parseTokenInfo(token);

            //删除用户权限缓存信息
            String permInfokey = (UserPermCacheConstant.SYS_USER_PERM_INFO_CACHE_KEY + tokenInfo.getUsername());
            redisTemplate.delete(permInfokey);

            //用户权限标识缓存集合
            String permsListkey = (UserPermCacheConstant.SYS_USER_PERMS_LIST_CACHE_KEY + tokenInfo.getUsername());
            redisTemplate.delete(permsListkey);
        } catch (Exception e) {
            log.warn("解析token错误:" + token);
        }
        return tokenInfo;
    }

    /**
     * 根据用户认证信息获取目录vo集合
     * @param tokenAuthInfo token认证信息
     * @return List<MenuVo>
     */
    public List<MenuVo> getDirectoryVoListByTokenAuthInfo(TokenAuthInfo tokenAuthInfo){
        List<MenuVo> directoryVoList = new ArrayList<>();
        List<Integer> typeList = new ArrayList<>();
        //是否管理员:0.否,1.是
        Integer isSys = tokenAuthInfo.getIsSys();
        HashMap<String, Object> map = new HashMap<>();
        //map.put("type", 1);//菜单类型:1.目录,2.菜单,3.tab页,4.按钮,5.超链接,6.后台接口,7.其他
        typeList.add(1);//菜单类型:1.目录,2.菜单,3.tab页,4.按钮,5.超链接,6.后台接口,7.其他
        typeList.add(2);//菜单类型:1.目录,2.菜单,3.tab页,4.按钮,5.超链接,6.后台接口,7.其他
        map.put("typeList", typeList);
        if(isSys == 1){
            directoryVoList = menuService.getVoListByMap(map);
        }else{
            map.put("username", tokenAuthInfo.getUsername());
            directoryVoList = userRoleService.getMenuVoListMap(map);
        }
        return menuService.buildTree("0", directoryVoList);
    }

    /**
     * 根据用户认证信息获取菜单vo集合
     * @param tokenAuthInfo token认证信息
     * @param parentId 父id
     * @return List<MenuVo>
     */
    public List<MenuVo> getMenuVoListByTokenAuthInfo(TokenAuthInfo tokenAuthInfo, String parentId){
        List<MenuVo> menuVoList = new ArrayList<>();
        //是否是系统内置,1:是,0:否
        Integer isSys = tokenAuthInfo.getIsSys();
        if(isSys == 1){
            MenuQuery menuQuery = new MenuQuery();
            menuQuery.setType(2);//菜单类型:1.目录,2.菜单,3.tab页,4.按钮,5.超链接,6.后台接口,7.其他
            menuVoList = menuService.treeTable(parentId, menuQuery);
        }else{
            menuVoList = userRoleService.getMenuVoTreeTableByTokenAuthInfo(tokenAuthInfo, parentId);
        }
        return menuVoList;
    }

    /**
     * 根据token认证获取权限标识集合
     * @param tokenAuthInfo
     * @return List<String>
     */
    @Cacheable(value = UserPermCacheConstant.SYS_USER_PERMS_LIST_CACHE_EXPIRE, key = "#tokenAuthInfo.username", unless = "#result == null ")
    public List<String> getPermsListByTokenAuthInfo(TokenAuthInfo tokenAuthInfo){
        List<String> permsList = new ArrayList<String>();
        //是否是系统内置,1:是,0:否
        Integer isSys = tokenAuthInfo.getIsSys();
        HashMap<String, Object> map = new HashMap<String, Object>();
        //系统管理员，拥有最高权限
        if(isSys == 1){
            permsList = menuDao.selectPermsListByMap(map);
        }else{
            map.put("username", tokenAuthInfo.getUsername());
            permsList = userRoleDao.selectPermsListByMap(map);
        }
        if(!CollectionUtils.isEmpty(permsList)){
            permsList = permsList.stream().filter(element -> element != null && !element.trim().isEmpty()).collect(Collectors.toList());
        }
        return permsList;
    }

    /**
     * 根据用户认证信息获取路由vo集合
     * @param tokenAuthInfo token认证信息
     * @return List<RouteVo>
     */
    public List<Route> getRouteListByTokenAuthInfo(TokenAuthInfo tokenAuthInfo){
        List<Route> rootRouteList = new ArrayList<>();

        Route rootRoute = buildRoute("/", "Home", "主页", null, new ArrayList<>());

        List<Route> routeList = new ArrayList<>();
        List<MenuVo> voList = new ArrayList<>();

        //是否管理员:0.否,1.是
        Integer isSys = tokenAuthInfo.getIsSys();
        HashMap<String, Object> map = new HashMap<>();
        List<Integer> typeList = new ArrayList<Integer>();
        typeList.add(1);//菜单类型:1.目录,2.菜单,3.tab页,4.按钮,5.超链接,6.后台接口,7.其他
        typeList.add(2);//菜单类型:1.目录,2.菜单,3.tab页,4.按钮,5.超链接,6.后台接口,7.其他
        map.put("typeList", typeList);
        //系统管理员，拥有最高权限
        if(isSys == 1){
            voList = menuDao.selectVoListByMap(map);
        }else{
            map.put("username", tokenAuthInfo.getUsername());
            voList = userRoleDao.selectMenuVoListMap(map);
        }
        if(CollectionUtils.isEmpty(voList)){
            rootRouteList.add(rootRoute);
            return rootRouteList;
        }
        Route route = null;
        for(MenuVo vo : voList){
            route = buildRoute(vo.getRoute(), vo.getUrl(), vo.getName(), vo.getIcon(), null);
            routeList.add(route);
        }
        rootRoute.setRedirect("/" + (StringUtils.isBlank(route.getPath()) ? "" : route.getPath()));
        rootRoute.setChildren(routeList);
        rootRouteList.add(rootRoute);
        return rootRouteList;
    }

    /**
     * 创建路由对象
     * @param path
     * @param component
     * @param title
     * @param icon
     * @param children
     * @return
     */
    private Route buildRoute(String path, String component, String title, String icon, List<Route> children){
        Meta meta = new Meta();
        meta.setTitle(title);
        meta.setIcon(icon);
        Route route = new Route();
        route.setPath(path);
        route.setComponent(component);
        route.setMeta(meta);
        route.setChildren(children);
        return route;
    }

    /**
     * 获取设置用户权限缓存
     * @param tokenInfo 用户token信息
     * @return UserPermInfo
     */
    private UserPermInfo getSetUserPermInfoCache(TokenInfo tokenInfo){
        UserPermInfo userPermInfo = new UserPermInfo();

        /**角色id集合*/
        List<String> roleIdList = new ArrayList<>();
        /**角色编码集合*/
        List<String> roleCodeList = new ArrayList<>();
        /**菜单id集合*/
        List<String> menuIdList = new ArrayList<>();
        /**权限标识集合*/
        List<String> permissionIdList = new ArrayList<>();
        //角色集合
        List<RoleEntity> roleList = new ArrayList<>();
        //菜单集合
        List<MenuEntity> menuList = new ArrayList<>();

        /**是否是系统内置,1:是,0:否*/
        Integer isSys = tokenInfo.getIsSys();
        if(isSys == 1){
            LambdaQueryWrapper<RoleEntity> rLqw = new LambdaQueryWrapper<RoleEntity>();
            roleList = roleDao.selectList(rLqw);

            LambdaQueryWrapper<MenuEntity> mLqw = new LambdaQueryWrapper<MenuEntity>();
            menuList = menuDao.selectList(mLqw);
        }else{
            HashMap<String, Object> map = new HashMap<String, Object>();
            map.put("username", tokenInfo.getUsername());
            roleList = userRoleDao.selectRoleEntityListByMap(map);

            menuList = userRoleDao.selectMenuEntityListByMap(map);
        }

        if(!CollectionUtils.isEmpty(roleList)){
            for(RoleEntity re : roleList){
                roleIdList.add(re.getId());
                roleCodeList.add(re.getCode());
            }
        }
        if(!CollectionUtils.isEmpty(menuList)){
            for(MenuEntity me : menuList){
                menuIdList.add(me.getId());
                permissionIdList.add(me.getPerms());
            }
        }

        userPermInfo.setUsername(tokenInfo.getUsername());
        userPermInfo.setRoleIdList(roleIdList);
        userPermInfo.setRoleCodeList(roleCodeList);
        userPermInfo.setMenuIdList(menuIdList);
        userPermInfo.setPermissionIdList(permissionIdList);
        return userPermInfo;
    }
}
